package org.tribot;

import org.tribot.difcontrol.R;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;

@SuppressLint("HandlerLeak")
public class ControlActivity extends Activity implements SensorEventListener, OnSeekBarChangeListener {
	
	// Debugging
    private static final String TAG = "LedController";
    private static final boolean D = false;
    
    // Message types sent from the BluetoothService Handler
    public static final int MESSAGE_STATE_CHANGE = 1;
    public static final int MESSAGE_READ = 2;
    public static final int MESSAGE_WRITE = 3;
    public static final int MESSAGE_DEVICE_NAME = 4;
    public static final int MESSAGE_TOAST = 5;

    // Key names received from the BluetoothService Handler
    public static final String DEVICE_NAME = "device_name";
    public static final String TOAST = "toast";

    // Intent request codes
    private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
    private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
    private static final int REQUEST_ENABLE_BT = 3;

    // Name of the connected device
    private String mConnectedDeviceName = null;
    // Local Bluetooth adapter
    private BluetoothAdapter mBluetoothAdapter = null;
    // Member object for the chat services
    private BluetoothService mBTService = null;
    
    // Sensors
    private SensorManager mSensorManager;
    private Sensor mAccelerometer;
    
    // Motores
    private boolean state;
    private int speed;
    public static final boolean ON = true;
    public static final boolean OFF = false;
    public static final int FORWARD = 0;
    public static final int REVERSE = 1;
    public static final int ROTATION_NOISE = 10;
    public static final int MAX_ROTATION = 80;
    public SeekBar speed_bar;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_control);
        
        // Get local Bluetooth adapter
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

        // If the adapter is null, then Bluetooth is not supported
        if (mBluetoothAdapter == null) {
            Toast.makeText(this, "Bluetoothmotor1 is not available", Toast.LENGTH_LONG).show();
            finish();
            return;
        }
        
        //Sensors Initialization        
        mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
        mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
        speed_bar = (SeekBar) findViewById(R.id.speed_bar);
        speed_bar.setOnSeekBarChangeListener(this);
    }
    
    @Override
    // On start activityfloat
    public void onStart() {
        super.onStart();
        // Debug tag
        if(D) Log.e(TAG, "++ ON START ++");

        // If BT is not on, reandroid accelerometerquest that it be enabled.
        // setupService() will then be called during onActivityResult
        if (!mBluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
        // Otherwise, setup the chat session
        } else {
            if (mBTService == null) setupService();
        }

		
    }        				
    
    @Override
    // On resume activity
    public synchronized void onResume() {
        super.onResume();
        // Debug tag
        if(D) Log.e(TAG, "+ ON RESUME +");

        // Performing this check in onResume() covers the case in which BT was2
        // not enabled during onStart(), so we were paused to enable it...
        // onResume() will be called when ACTION_REQUEST_ENABLE activity returns.
        if (mBTService != null) {
            // Only if the state is STATE_NONE, do we know that we haven't started already
            if (mBTService.getState() == BluetoothService.STATE_NONE) {
              // Start the Bluetooth chat services
              mBTService.start();
            }
        }
        mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
    }

    private void setupService() {
        Log.d(TAG, "setupChat()");

        // Initialize the BluetoothChatService to perform bluetooth connections
        mBTService = new BluetoothService(this, mHandler);

    }

    @Override
    // On pause activity
    public synchronized void onPause() {
        super.onPause();
        if(D) Log.e(TAG, "- ON PAUSE -");
        mSensorManager.unregisterListener(this);
    }

    @Override
    // On stop activity
    public void onStop() {
        super.onStop();
        if(D) Log.e(TAG, "-- ON STOP --");
    }

    @Override
    // On destroy activity
    public void onDestroy() {
        super.onDestroy();
        // Stop the Bluetooth chat services
        if (mBTService != null) mBTService.stop();
        if(D) Log.e(TAG, "--- ON DESTROY ---");
    }

    private void ensureDiscoverable() {
    	// Debug tagFORWARD
        if(D) Log.d(TAG, "ensure discoverable");
        // Activate the discoverable mode for another device to find it
        if (mBluetoothAdapter.getScanMode() !=
            BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
            Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
            discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
            startActivity(discoverableIntent);
        }
    }
    
    /**
     * Sends a message.
     * @param message  A string of text to send.
     */
    private void sendMessage(byte[] Bytes) {
        // Check that we're actually connected before trying anything
        if (mBTService.getState() != BluetoothService.STATE_CONNECTED) {
            Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();
            return;
            }

        // Get the message bytes and tell the BluetoothChatService to write
        mBTService.write(Bytes);

    }
    
    // Functions for setting the connection status label
    private final void setStatus(int resId) {
    	TextView label = (TextView) findViewById(R.id.conection_status);
    	label.setText(resId);
    }
    private final void setStatus(CharSequence subTitle) {
    	TextView label = (TextView) findViewById(R.id.conection_status);
    	label.setText(subTitle);
    }

    // The Handler that gets information back from the BluetoothChatService
    // Depending of the message received it calls setStatus with a different message
	private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MESSAGE_STATE_CHANGE:
                if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
                switch (msg.arg1) {
                case BluetoothService.STATE_CONNECTED:
                    setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
                    break;
                case BluetoothService.STATE_CONNECTING:
                    setStatus(R.string.title_connecting);
                    break;
                case BluetoothService.STATE_LISTEN:
                case BluetoothService.STATE_NONE:
                    setStatus(R.string.title_not_connected);
                    break;
                }
                break;
            case MESSAGE_WRITE:
                break;
            case MESSAGE_READ:
                break;
            case MESSAGE_DEVICE_NAME:
                // save the connected device's name
                mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
                Toast.makeText(getApplicationContext(), "Connected to "
                               + mConnectedDeviceName, Toast.LENGTH_SHORT).show();
                break;
            case MESSAGE_TOAST:
                Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
                               Toast.LENGTH_SHORT).show();
                break;
            }
        }
    };
    
    // After calling the activity from the menu, verifies if the return was OK
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(D) Log.d(TAG, "onActivityResult " + resultCode);
        switch (requestCode) {
        case REQUEST_CONNECT_DEVICE_SECURE:
            // When DeviceListActivity returns with a device to connect
            if (resultCode == Activity.RESULT_OK) {
                connectDevice(data, true);
            }
            break;
        case REQUEST_CONNECT_DEVICE_INSECURE:
            // When DeviceListActivity returns with a device to connect
            if (resultCode == Activity.RESULT_OK) {
                connectDevice(data, false);
            }
            break;
        case REQUEST_ENABLE_BT:
            // When the request to enable Bluetooth returns
            if (resultCode == Activity.RESULT_OK) {
                // Bluetooth is now enabled, so set up a chat session
                setupService();
            } else {
                // User did not enable BluensorManager.SENSOR_DELAY_NORMAL);tooth or an error occurred
                Log.d(TAG, "BT not enabled");
                Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
                finish();
            }
        }
    }

    // Request for connection to the device, secure or insecure 
    private void connectDevice(Intent data, boolean secure) {
        // Get the device MAC address
        String address = data.getExtras()
            .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
        // Get the BluetoothDevice object
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        // Attempt to connect to the device
        mBTService.connect(device, secure);
    }
    
    // Menu configuration
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.option_menu, menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Intent serverIntent = null;
        switch (item.getItemId()) {
        case R.id.secure_connect_scan:
            // Launch the DeviceListActivity to see devices and do scan
            serverIntent = new Intent(this, DeviceListActivity.class);
            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
            return true;
        case R.id.insecure_connect_scan:
            // Launch the DeviceListActivity to see devices and do scanFORWARD
            serverIntent = new Intent(this, DeviceListActivity.class);
            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);
            return true;
        case R.id.discoverable:
            // Ensure this device is discoverable by others
            ensureDiscoverable();
            return true;
        }
        return false;
    }
    
    /* *******************************
     * FINAL DE CONFIGURACION INICIAL
     *********************************/
    
    
    /*FUNCIONES DE CONFIGURACION DE MOTORES*/
    
    public byte getMotorByte(int num, int dir){
    	byte Byte = 0; 
    	
    	switch(num){
		case 1 :	Byte = (byte) 0x01;
					break;
		case 2 :	Byte = (byte) 0x02;
					break;
		case 3 :	Byte = (byte) 0x03;
					break;
		}
		Byte =(byte) ((byte) Byte<<1);
		// If direction button is checked bit0 is 1, if not bit0 is 0
		if(dir == REVERSE) Byte =(byte) (Byte | 0x1);
		else Byte =(byte) (Byte | 0x0);
    	
    	return Byte;
    }
    
    /*CONFIGURACION CONTROLES*/
    
    public void TurnOnBot(){
    	byte[] send = new byte[4];
		send[0] = (byte) 0x80;
		send[3] = (byte) 0xF0;
		send[2] = (byte) 0x00; //VELOCIDAD INICIAL
		send[1] = getMotorByte(1,REVERSE);
		sendMessage(send);
		send[1] = getMotorByte(3,FORWARD);
		sendMessage(send);
		
		speed = 0; //VELOCIDAD INICIAL EN DECIMAL
		state = ON;
		speed_bar.setProgress(0);
    }
    
    public void TurnOffBot(){
    	byte[] send = new byte[4];
		send[0] = (byte) 0x80;
		send[3] = (byte) 0xF0;
		send[2] = (byte) 0x00;
		send[1] = getMotorByte(1,REVERSE);
		sendMessage(send);
		send[1] = getMotorByte(3,FORWARD);
		sendMessage(send);
		
		speed = 0;
		state = OFF;	
		speed_bar.setProgress(0);
    }
    
    public void startButton(View v){
    	ToggleButton Button = (ToggleButton) findViewById(R.id.start_button);
    	if(Button.isChecked()) TurnOnBot();
    	else TurnOffBot();
    }
    
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
		// TODO Auto-generated method stub
		
	}

	public void onSensorChanged(SensorEvent event) {
		// TODO Auto-generated method stub
		TextView textX= (TextView) findViewById(R.id.xaxis);
		TextView textY= (TextView) findViewById(R.id.yaxis);
		TextView textZ= (TextView) findViewById(R.id.zaxis);

		float z = event.values[0];
		float x = event.values[1];
		float y = event.values[2];
		float factor;
		int newSpeed;
		
		//TEST AREA
		if(state){
			byte[] send = new byte[4];
			send[0] = (byte) 0x80;
			send[3] = (byte) 0xF0;
			
			if(x > MAX_ROTATION) x = MAX_ROTATION; // LIMITES DE ANGULO
			if(x < (-MAX_ROTATION)) x = (-MAX_ROTATION);
			if(x>(-ROTATION_NOISE) && x<ROTATION_NOISE) x = 0;
			
			if(x > 0){
				
				factor = x;
				
				send[1] = getMotorByte(1,REVERSE);
				newSpeed = speed - (int) (factor*speed)/MAX_ROTATION;
				send[2] = (byte) newSpeed;
				sendMessage(send);
				
				send[1] = getMotorByte(3,FORWARD);
				send[2] = (byte) speed;
				sendMessage(send);	
				
			} else {
				
				factor = -x;
				
				send[1] = getMotorByte(1,REVERSE);
				send[2] = (byte) speed;
				sendMessage(send);
				
				send[1] = getMotorByte(3,FORWARD);
				newSpeed = speed - (int) (factor*speed)/MAX_ROTATION;
				send[2] = (byte) newSpeed;
				sendMessage(send);
			}
			
		}
		
		//END OF TEST AREA
		
		textX.setText(Float.toString(x));
		textY.setText(Float.toString(y));
		textZ.setText(Float.toString(z));
		
		
	}
	
	public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
		// TODO Auto-generated method stub		
		byte[] send = new byte[4];
		
		if(state){
		
			speed = progress;
			
			send[0] = (byte) 0x80;
			send[3] = (byte) 0xF0;
			send[2] = (byte) (speed);
			
			send[1] = getMotorByte(1,REVERSE);
			sendMessage(send);
			send[1] = getMotorByte(3,FORWARD);
			sendMessage(send);
		}
		
	}

	public void onStartTrackingTouch(SeekBar arg0) {
		// TODO Auto-generated method stub
		
	}

	public void onStopTrackingTouch(SeekBar arg0) {
		// TODO Auto-generated method stub
		
	}
    
}
